﻿using System;
using System.IO;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using OSM;

namespace OSMConvert
{
	class ProgressEntry
	{
		public string Code, FileName;
		public DateTime indextime;
		List<Tuple<long, long>> Indices = new List<Tuple<long, long>>();

		public override string ToString()
		{
			return Code + "\t" + FileName + "\t" + indextime.ToBinary();
		}

		public ProgressEntry(string c, string fn, DateTime it)
		{
			Code = c;
			FileName = fn;
			indextime = it;
		}
		public ProgressEntry(params string[] fields)
			: this(fields[0], fields[1], DateTime.FromBinary(long.Parse(fields[2])))
		{
		}

		public bool Indexed
		{
			get
			{
				if (!File.Exists(Code + ".idx"))
					return false;
				FileInfo fi = new FileInfo(OSMCore.OSMPath + FileName);
				if (fi.LastWriteTime != indextime)
					return false;
				return true;
			}
		}
		public bool Converted
		{
			get
			{
				return Directory.Exists(OSMCore.OSMPath + Code + "\\");
			}
		}
		public bool Admin
		{
			get
			{
				return Directory.Exists(OSMCore.OSMPath + Code + "_admin\\");
			}
		}
		void LoadIndex()
		{
			Indices.Clear();
			string[] buf = File.ReadAllLines(Code + ".idx");
			foreach (var row in buf)
			{
				string[] x = row.Split(' ');
				Indices.Add(new Tuple<long, long>(long.Parse(x[0]), long.Parse(x[1])));
			}
		}
		void SaveIndex()
		{
			List<string> buf = new List<string>();
			foreach (var row in Indices)
				buf.Add(row.Item1 + " " + row.Item2);
			File.WriteAllLines(Code + ".idx", buf.ToArray());
		}
		public void MakeIndex()
		{
			Indices.Clear();
			if (Indexed)
			{
				LoadIndex();
				Console.WriteLine("Up to date");
			}
			else
			{
				int CX = Console.CursorLeft;
				Indices = OSMData.GetRowCnt(OSMCore.OSMPath + FileName, x =>
				{
					Console.CursorLeft = CX;
					Console.Write(x.ToString());
				});
				Console.CursorLeft = CX;
				SaveIndex();
				indextime = new FileInfo(OSMCore.OSMPath + FileName).LastWriteTime;
				Console.WriteLine("Updated: " + indextime.ToString());
			}
		}

		public bool MakeConvert(Action<int> onprg)
		{
			if (Converted)
			{
				onprg(-1);
				return false;
			}
			else
			{
				MakeIndex();
				string output = "C:\\OSMData\\" + Code + "\\";
				if (Directory.Exists(output))
					Console.WriteLine(Code + " exists, skipped");
				else
				{
					Directory.CreateDirectory(output);
					OSMData.ConvertOSM(Code, OSMCore.OSMPath + FileName, output, Code, x =>
					{
						//Console.CursorLeft = 0;
						//Console.Write(Code + ": " + ((x[0] / 10.0).ToString("0.0") + "%").PadLeft(10)
						//	+ " " + x[1].ToString().PadLeft(10)
						//	+ " " + x[2].ToString().PadLeft(10)
						//	+ " " + x[3].ToString().PadLeft(10));
						onprg(x[0]);
					});
					Console.WriteLine();
				}
				return true;
			}
		}

		public void MakeAdmin(Action<int>onprg)
		{
			if (Admin)
			{
			}
			else
			{
				OSMData D = new OSMData();
				String Dir = OSMCore.OSMPath + Code + "\\";
				//Get admin_level keys for administrative relations
				onprg(0);
				String FN1 = OSMCore.OSMPath + Code + "\\relation_tags.bin";
				String[] Buf_tag = File.ReadAllLines(FN1);
				List<long> admins = new List<long>();
				for (int i = 0; i < Buf_tag.Length; i++)
					if (Buf_tag[i].Contains("\t\"admin_level\"\t"))
					{
						admins.Add(long.Parse(Buf_tag[i].Split('\t')[0]));
					}
				//Fill up relations
				foreach (long id in admins)
					D.RelID.Add(id, new OSMRelation(id));
				//Load selected relations members and tags
				D.LoadRelationMembers(Dir, false);
				OSMData.LoadTags(D.RelID, FN1);
				//Create empty ways from relation members
				onprg(1);
				foreach (OSMRelation rel in D.RelID.Values)
				{
					rel.Members.FindAll(x => x.Type == "way").ForEach(x =>
					{
						if (!D.WayID.ContainsKey(x.Ref))
							D.WayID.Add(x.Ref, new OSMWay(x.Ref));
					});
				}
				//Load ways tags
				String FN2 = OSMCore.OSMPath + Code + "\\way_tags.bin";
				OSMData.LoadTags(D.WayID, FN2);
				//Load nodes contained by ways
				onprg(2);
				D.LoadWayNodes(Dir, false);

				foreach (var w in D.WayID.Values)
				{
					foreach (long id in w.Nodes)
						D.AddNodeC(id, double.NaN, double.NaN);
				}
				foreach (var rel in D.RelID)
					foreach (var x in rel.Value.Members)
					{
						if (x.Role == "admin_centre")
							D.AddNodeC(x.Ref, double.NaN, double.NaN);
					}
				//Load node data and tags
				D.ReloadNodes(Dir);
				//String FN3 = OSMCore.OSMPath + s + "\\node_tags.bin";
				//OSMData.LoadTags(D.NodeID, FN3);
				//Link objects
				onprg(3);
				D.BuildLink();
				string AdminPath = OSMCore.OSMPath + Code + "_admin";
				if (!Directory.Exists(AdminPath))
					Directory.CreateDirectory(AdminPath);
				D.Save(AdminPath + "\\");
				onprg(4);
				//Console.WriteLine(Code + " extracted");
			}
		}
	}
}